#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdarg.h>
#include "os.h"
#include "dec_api.h"
#include "Usb_ts_play.h"

typedef enum
{
	MPEG_ES_TYPE_RESERVED     = 0x00,
	MPEG_ES_TYPE_MPEG1_VIDEO  = 0x01,
	MPEG_ES_TYPE_MPEG2_VIDEO  = 0x02,
	MPEG_ES_TYPE_MPEG1_AUDIO  = 0x03,
	MPEG_ES_TYPE_MPEG2_AUDIO  = 0x04,
	MPEG_ES_TYPE_PRIVATE_SEC  = 0x05,
	MPEG_ES_TYPE_PRIVATE_PES  = 0x06,
	MPEG_ES_TYPE_MHEG         = 0x07,
	MPEG_ES_TYPE_DSM_CC       = 0x08,
	MPEG_ES_TYPE_H222         = 0x09,
	MPEG_ES_TYPE_13818_6_A    = 0x0A,
	MPEG_ES_TYPE_13818_6_B    = 0x0B,
	MPEG_ES_TYPE_13818_6_C    = 0x0C,
	MPEG_ES_TYPE_13818_6_D    = 0x0D,
	MPEG_ES_TYPE_AUX          = 0x0E,
	MPEG_ES_TYPE_MPEG4_VIDEO  = 0x1B,
	MPEG_ES_TYPE_VIDEO_HEVC	= 0x24, 	//Definition of 0x24 HEVC video MPEG TS stream type
	MPEG_ES_TYPE_VIDEO_CAVS 	= 0x42, 	//avs
	ATSC_DOLBY_DIGITAL        = 0x81,
	MPEG_ES_TYPE_DTS_AUDIO 	= 0x82,
	MPEG_ES_TYPE_AAC        = 0x11,
	MPEG_ES_TYPE_AAC1        = 0x0F,
} stream_type;

//dll:extern TAPI_BOOL  Tapi_TsPlay_Init( );
typedef TAPI_BOOL (*pfTsPlayInit)();

//dll:extern TAPI_BOOL  Tapi_TsPlay_Deinit( );
typedef TAPI_BOOL (*pfTsPlayDeinit)();

//dll:extern TAPI_BOOL  Tapi_TsPlay_Start( );
typedef TAPI_BOOL (*pfTsPlayStart)();

//dll:extern TAPI_BOOL  Tapi_TsPlay_Stop( );
typedef TAPI_BOOL (*pfTsPlayStop)();

//dll:extern TAPI_BOOL  Tapi_TsPlay_PushData( void *data, TAPI_U32 data_len );
typedef TAPI_BOOL (*pfTsPlayPushData)(void *data, TAPI_U32 data_len);

//dll:TAPI_BOOL  Tapi_TsPlay_SetParam( ST_TS_PLAY_PARAM* stTsPlayParam ); 
typedef TAPI_BOOL (*pfTsPlaySetParam)(ST_TS_PLAY_PARAM* stTsPlayParam);

//dll:TAPI_BOOL  Tapi_TsPlay_SetFreezingChangingChannel( TAPI_BOOL  bFreeze );
typedef TAPI_BOOL (*pfTsPlaySetChannelChgMode)(TAPI_BOOL  bFreeze);

//dll:extern TAPI_BOOL  Tapi_TsPlay_SetWindow( ST_VIDEO_WINDOW_TYPE* stVidWindowType );	
typedef TAPI_BOOL (*pfTsPlaySetWindow)(ST_VIDEO_WINDOW_TYPE* stVidWindowType);

//dll:extern TAPI_BOOL  Tapi_TsPlay_GetWindow( ST_VIDEO_WINDOW_TYPE* stVidWindowType );
typedef TAPI_BOOL (*pfTsPlayGetWindow)(ST_VIDEO_WINDOW_TYPE* stVidWindowType);

//dll:extern TAPI_BOOL  Tapi_TsPlay_SetSoundMode( EN_AUD_SOUNDMODE_TYPE* enAudModeType );
typedef TAPI_BOOL (*pfTsPlaySetAudioTrack)(EN_AUD_SOUNDMODE_TYPE* enAudModeType);

//dll:TAPI_BOOL  Tapi_TsPlay_ScreenClear();
typedef TAPI_BOOL (*pfTsPlayClearVideo)();


pfTsPlayInit s_pfInit = NULL;
pfTsPlayDeinit s_pfDeinit = NULL;
pfTsPlayPushData s_pfPushData = NULL;
pfTsPlayStart s_pfStart = NULL;
pfTsPlayStop s_pfStop = NULL;
pfTsPlaySetChannelChgMode s_pfSetChannelChgMode = NULL;
pfTsPlaySetWindow s_pfSetWindow = NULL;
pfTsPlayGetWindow s_pfGetWindow = NULL;
pfTsPlaySetAudioTrack s_pfSetAudioTrack = NULL;
pfTsPlaySetParam s_pfSetParam = NULL;
pfTsPlayClearVideo s_pfClearVideo = NULL;

static unsigned char s_u8Init = 0;
static unsigned char s_u8DecoderPlaying = 0;
static unsigned int s_u32DecMutex = 0;

pfDecNotifyPlayer g_pfDecNotification = NULL; 

int DVBDecoderRegisterStartPlayerFun(pfDecNotifyPlayer pfDecNotification)
{
	SM_Printf("DVBDecoderRegisterStartPlayerFun() - entry\r\n");
	g_pfDecNotification = pfDecNotification;
	SM_Printf("DVBDecoderRegisterStartPlayerFun() - return\r\n");
	return 0;
}

int DVBDecoderInit()
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderInit() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_u8Init == 0)
	{
		if(s_pfInit)
		{
			SM_Printf("DVBDecoderInit() - call Tapi_TsPlay_Init\r\n");
			s32Rc = s_pfInit();
		}
		s_u8Init = 1;
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderInit() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex, s32Rc);
	
	return s32Rc;
}

int DVBDecoderDeinit()
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderDeinit() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_u8Init == 1)
	{
		if(s_pfStop)
		{
			if(s_u8DecoderPlaying == 1)
			{
				s32Rc = s_pfStop();
				s_u8DecoderPlaying = 0;
			}
			else
				SM_Printf("DVBDecoderDeinit() - call dal_tsplay_stop error\r\n");
		}
		
		if(s_pfDeinit)
		{
			SM_Printf("DVBDecoderDeinit() - call Tapi_TsPlay_Deinit\r\n");
			s32Rc = s_pfDeinit();
		}
		s_u8Init = 0;
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderDeinit() - return s_u32DecMutex = %d, s32Rc=%d\r\n", s_u32DecMutex, s32Rc);
	
	return s32Rc;
}

int DVBDecoderPushData(unsigned char *pu8Data, unsigned int u32Len)
{
	int s32Rc = -1;

	if(s_u32DecMutex != 2)
		SM_Printf("DVBDecoderPushData() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfPushData && s_u8DecoderPlaying == 1)
		s32Rc = s_pfPushData(pu8Data, u32Len);
	else
		SM_Printf("DVBDecoderPushData() - error s_pfPushData = %p, s_u8DecoderPlaying = %d\r\n", s_pfPushData, s_u8DecoderPlaying);
	SM_OsSemRelease(&s_u32DecMutex);
	if(s_u32DecMutex != 2)
		SM_Printf("DVBDecoderPushData() - return s_u32DecMutex = %d\r\n", s_u32DecMutex);
	
	return s32Rc;
}

int DVBDecoderStart()
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderStart() entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_u8Init == 0)
	{
		if(s_pfInit)
		{
			SM_Printf("DVBDecoderStart() - call Tapi_TsPlay_Init\r\n");
			s32Rc = s_pfInit();
		}
		s_u8Init = 1;
	}

	if(s_pfStart)
	{
		if(s_u8DecoderPlaying == 0)
		{
			s32Rc = s_pfStart();
			s_u8DecoderPlaying = 1;
		}
		else
			SM_Printf("DVBDecoderStart() - call dal_tsplay_start error\r\n");
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderStart() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderStop()
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderStop() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfStop)
	{
		if(s_u8DecoderPlaying == 1)
		{
			s32Rc = s_pfStop();
			s_u8DecoderPlaying = 0;
		}
		else
			SM_Printf("DVBDecoderStop() - call Tapi_TsPlay_Stop error\r\n");
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderStop() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderAVFreeze(int s32Enble)
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderAVFreeze() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfSetChannelChgMode)
		s32Rc = s_pfSetChannelChgMode(s32Enble);
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderAVFreeze() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderSetWindows(unsigned int u32X, unsigned int u32Y, unsigned int u32Width, unsigned int u32Hight)
{
	int s32Rc = -1;
	ST_VIDEO_WINDOW_TYPE stWindows;

	SM_Printf("DVBDecoderSetWindows() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	stWindows.x = u32X;
	stWindows.y = u32Y;
	stWindows.hight = u32Hight;
	stWindows.width = u32Width;
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfSetWindow)
		s32Rc = s_pfSetWindow(&stWindows);
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderSetWindows() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderGetWindows(unsigned int* pu32X, unsigned int* pu32Y, unsigned int* pu32Width, unsigned int* pu32Hight)
{
	int s32Rc = -1;
	ST_VIDEO_WINDOW_TYPE stWindows;

	SM_Printf("DVBDecoderGetWindows() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	if(pu32X && pu32Y && pu32Width && pu32Hight)
	{
		memset(&stWindows, 0, sizeof(stWindows));
		*pu32X = 0;
		*pu32Y = 0;
		*pu32Width = 0;
		*pu32Hight = 0;
		SM_OsSemWait(&s_u32DecMutex, -1);
		if(s_pfGetWindow)
		{
			s32Rc = s_pfGetWindow(&stWindows);
			if(s32Rc == 0)
			{
				*pu32X = stWindows.x;
				*pu32Y = stWindows.y;
				*pu32Width = stWindows.width;
				*pu32Hight = stWindows.hight;
			}
		}
		SM_OsSemRelease(&s_u32DecMutex);
	}
	SM_Printf("DVBDecoderGetWindows() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderSetAudioTrack(DEC_AUDIO_TRACK_T eType)
{
	int s32Rc = -1;
	EN_AUD_SOUNDMODE_TYPE eAudModeType;

	SM_Printf("DVBDecoderSetAudioTrack() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfSetAudioTrack)
	{
		switch(eType)
		{
			case DEC_AUDIO_TRACK_LEFT:
				eAudModeType = EN_AUD_SOUNDMODE_LEFT;
				break;
			case DEC_AUDIO_TRACK_RIGHT:
				eAudModeType = EN_AUD_SOUNDMODE_RIGHT;
				break;
			case DEC_AUDIO_TRACK_STEREO:
				eAudModeType = EN_AUD_SOUNDMODE_STEREO;
				break;
		}
		s32Rc = s_pfSetAudioTrack(&eAudModeType);
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderSetAudioTrack() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderSetParam(unsigned short u16PcrPid, unsigned short u16VidPid, unsigned int VidType, unsigned short u16AudPid, unsigned int AudType)
{
	int s32Rc = -1;
	EN_VID_CODE_TYPE eVideoType;
	EN_AUD_CODE_TYPE eAudioType;
	ST_TS_PLAY_PARAM stTsParam;

	SM_Printf("DVBDecoderSetParam() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	memset(&stTsParam, 0, sizeof(stTsParam));
	
	if(s_u8Init == 0)
	{
		if(s_pfInit)
		{
			SM_Printf("DVBDecoderSetParam() - call Tapi_TsPlay_Init\r\n");
			s32Rc = s_pfInit();
			SM_Printf("DVBDecoderSetParam() - call Tapi_TsPlay_Init ,s32Rc=%d\r\n",s32Rc);
			if(g_pfDecNotification)
				g_pfDecNotification(DEC_INIT_DONE);
		}
		s_u8Init = 1;
	}
	
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfSetParam)
	{
		switch(VidType)
		{
			case MPEG_ES_TYPE_MPEG1_VIDEO:
				eVideoType = EN_VID_CODE_TYPE_MPEG2;
				break;
			case MPEG_ES_TYPE_MPEG2_VIDEO:
				eVideoType = EN_VID_CODE_TYPE_MPEG2;
				break;
			case MPEG_ES_TYPE_MPEG4_VIDEO:
				eVideoType = EN_VID_CODE_TYPE_H264;
				break;
			case MPEG_ES_TYPE_VIDEO_HEVC:
				eVideoType = EN_VID_CODE_TYPE_H265;
				break;
			case MPEG_ES_TYPE_VIDEO_CAVS:
				eVideoType = EN_VID_CODE_TYPE_AVS;
				break;
			default:
				eVideoType = EN_VID_CODE_TYPE_MPEG2;
				break;
		}

		switch(AudType)
		{
			case MPEG_ES_TYPE_MPEG1_AUDIO:
				eAudioType = EN_AUD_CODE_TYPE_MPEG;
				break;
			case MPEG_ES_TYPE_MPEG2_AUDIO:
				eAudioType = EN_AUD_CODE_TYPE_MPEG;
				break;
			case MPEG_ES_TYPE_AAC:
				eAudioType = EN_AUD_CODE_TYPE_AAC;
				break;
			case MPEG_ES_TYPE_AAC1:
				eAudioType = EN_AUD_CODE_TYPE_AAC;
				break;
			case MPEG_ES_TYPE_PRIVATE_PES://reserve considered as ac3
				eAudioType = EN_AUD_CODE_TYPE_AC3;
				break;
			case ATSC_DOLBY_DIGITAL:
				eAudioType = EN_AUD_CODE_TYPE_AC3;
				break;
			case MPEG_ES_TYPE_DTS_AUDIO:
				eAudioType = EN_AUD_CODE_TYPE_DTS;
				break;
			default:
				eAudioType = EN_AUD_CODE_TYPE_MPEG;
				u16AudPid = 0x1fff;
				break;
		}
		stTsParam.Audio_CodeType = eAudioType;
		stTsParam.Audio_Pid = u16AudPid;
		stTsParam.PCR_Pid = u16PcrPid;
		stTsParam.Video_CodeType = eVideoType;
		stTsParam.Video_Pid = u16VidPid;
		s32Rc = s_pfSetParam(&stTsParam);
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderSetParam() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	return s32Rc;
}

int DVBDecoderClearVideo()
{
	int s32Rc = -1;

	SM_Printf("DVBDecoderClearVideo() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	SM_OsSemWait(&s_u32DecMutex, -1);
	if(s_pfClearVideo && s_u8Init == 1)
	{
		if(s_u8DecoderPlaying == 1)
		{
			s32Rc = s_pfStop();
			s32Rc = s_pfClearVideo();
			s32Rc = s_pfStart();
		}
		else
			s32Rc = s_pfClearVideo();
	}
	SM_OsSemRelease(&s_u32DecMutex);
	SM_Printf("DVBDecoderClearVideo() - return s_u32DecMutex = %d,s32Rc=%d\r\n", s_u32DecMutex,s32Rc);
	
	return s32Rc;
}

int DVBDecoderLoadSymbol()
{
	void *handle;
	int s32Rc = 0;

	SM_Printf("DVBDecoderLoadSymbol() - entry s_u32DecMutex = %d\r\n", s_u32DecMutex);
	handle = dlopen("/system/lib/libicast_hal_tsplayer.so", RTLD_LAZY);
	if(handle == NULL)
	{
		SM_Printf("DVBDecoderLoadSymbol() - load /system/lib/libicast_hal_tsplayer.so error, %s:%s\r\n", strerror(errno), dlerror());
		handle = dlopen("/system/lib/libMediaPlayCtrl.so", RTLD_LAZY);
	}
	if(handle == NULL)
	{
		SM_Printf("DVBDecoderLoadSymbol() - load /system/lib/libMediaPlayCtrl.so error, %s:%s\r\n", strerror(errno), dlerror());
		handle = dlopen("/system/lib/libhdiapi.so", RTLD_LAZY);
	}

	if(handle)
	{
		s_pfInit = (pfTsPlayInit)dlsym(handle, "Tapi_TsPlay_Init");
		if(s_pfInit == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_Init failed\r\n");
			s32Rc = -1;
		}
		
		s_pfDeinit = (pfTsPlayDeinit)dlsym(handle, "Tapi_TsPlay_Deinit");
		if(s_pfDeinit == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_Deinit failed\r\n");
			s32Rc = -1;
		}
		
		s_pfPushData = (pfTsPlayPushData)dlsym(handle, "Tapi_TsPlay_PushData");
		if(s_pfPushData == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_PushData failed\r\n");
			s32Rc = -1;
		}
		
		s_pfStart = (pfTsPlayStart)dlsym(handle, "Tapi_TsPlay_Start");
		if(s_pfStart == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_Start failed\r\n");
			s32Rc = -1;
		}
		
		s_pfStop = (pfTsPlayStop)dlsym(handle, "Tapi_TsPlay_Stop");
		if(s_pfStop == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_Stop failed\r\n");
			s32Rc = -1;
		}
				
		s_pfSetChannelChgMode = (pfTsPlaySetChannelChgMode)dlsym(handle, "Tapi_TsPlay_SetFreezingChangingChannel");
		if(s_pfSetChannelChgMode == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_SetFreezingChangingChannel failed\r\n");
			s32Rc = -1;
		}
				
		s_pfSetWindow = (pfTsPlaySetWindow)dlsym(handle, "Tapi_TsPlay_SetWindow");
		if(s_pfSetWindow == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_SetWindow failed\r\n");
			s32Rc = -1;
		}
		
		s_pfGetWindow = (pfTsPlayGetWindow)dlsym(handle, "Tapi_TsPlay_GetWindow");
		if(s_pfGetWindow == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_GetWindow failed\r\n");
			s32Rc = -1;
		}
		
		s_pfSetAudioTrack = (pfTsPlaySetAudioTrack)dlsym(handle, "Tapi_TsPlay_SetSoundMode");
		if(s_pfSetAudioTrack == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_SetSoundMode failed\r\n");
			s32Rc = -1;
		}
				
		s_pfSetParam = (pfTsPlaySetParam)dlsym(handle, "Tapi_TsPlay_SetParam");
		if(s_pfSetParam == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_SetParam failed\r\n");
			s32Rc = -1;
		}

		s_pfClearVideo = (pfTsPlaySetParam)dlsym(handle, "Tapi_TsPlay_ScreenClear");
		if(s_pfClearVideo == NULL)
		{
			SM_Printf("DVBDecoderLoadSymbol() - load function: Tapi_TsPlay_ScreenClear failed\r\n");
			s32Rc = -1;
		}
	}
	else
	{
		SM_Printf("DVBDecoderLoadSymbol() - load /system/lib/libhdiapi.so error, %s:%s\r\n", strerror(errno), dlerror());
		s32Rc = -1;
	}

	//if(s32Rc == 0)
	SM_OsSemCreate(&s_u32DecMutex, NULL, 1);
	if(s32Rc == -1)
	{
		s_pfInit = NULL;
		s_pfDeinit = NULL;
		s_pfPushData = NULL;
		s_pfStart = NULL;
		s_pfStop = NULL;
		s_pfSetChannelChgMode = NULL;
		s_pfSetWindow = NULL;
		s_pfGetWindow = NULL;
		s_pfSetAudioTrack = NULL;
		s_pfSetParam = NULL;
		s_pfClearVideo = NULL;
	}

	SM_Printf("DVBDecoderLoadSymbol() - return s32Rc = %d\r\n", s32Rc);
	return s32Rc;
}

